package com.flsldl.mydb.backend.tm;

import com.flsldl.mydb.backend.utils.Panic;
import com.flsldl.mydb.common.Error;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @ClassName TransactionManager
 * @Description TODO
 * @Author @O_o @Date 2023/2/14 下午 8:11
 *
 * 提供了一些接口供其他模块调用，用来创建事务和查询事务状态。
 */
public interface TransactionManager {

    //开启一个新事务
    long begin();

    //提交一个事务
    void commit(long xid);

    //取消一个事务
    void abort(long xid);

    //查询一个事务的状态是否是正在进行的状态
    boolean isActive(long xid);

    //查询一个事务的状态是否是已提交
    boolean isCommitted(long xid);

    //查询一个事务的状态是否是已取消
    boolean isAborted(long xid);

    //关闭 TM
    void close();

    // 创建一个 xid 文件并创建 TM
    public static TransactionManagerImpl create(String path) {
        // 创建一个 XID 文件对象
        File f = new File(path + TransactionManagerImpl.XID_SUFFIX);
        // 新建 XID 文件
        try {
            if (!f.createNewFile()) {
                Panic.panic(Error.FileExistsException);
            }
        } catch (Exception e) {
            Panic.panic(e);
        }
        // 判断读写权限
        if (!f.canRead() || !f.canWrite()) {
            Panic.panic(Error.FileCannotRWException);
        }
        FileChannel fc = null;
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(f,"rw");
            fc = raf.getChannel();
        } catch (FileNotFoundException e) {
            Panic.panic(e);
        }

        // 写空 XID 文件头
        ByteBuffer buf = ByteBuffer.wrap(new byte[TransactionManagerImpl.LEN_XID_HEADER_LENGTH]);
        try {
            fc.position(0);
            fc.write(buf);
        } catch (IOException e) {
            Panic.panic(e);
        }
        return new TransactionManagerImpl(raf, fc);
    }

    // 从一个已有的 xid 文件来创建 TM
    public static TransactionManagerImpl open(String path) {
        File f = new File(path + TransactionManagerImpl.XID_SUFFIX);
        if (!f.exists()) {
            Panic.panic(Error.FileNotExistsException);
        }
        if (!f.canRead() || !f.canWrite()) {
            Panic.panic(Error.FileCannotRWException);
        }

        FileChannel fc = null;
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(f, "rw");
            fc = raf.getChannel();
        } catch (FileNotFoundException e) {
            Panic.panic(e);
        }

        return new TransactionManagerImpl(raf, fc);
    }
}
